#pragma once
#include "Thread.hpp"
#include "LockGuard.hpp"
#include"log.hpp"
#include <vector>
#include<queue>
#include <pthread.h>
#include<unistd.h>
#include<mutex>
using namespace threadNs;
const int gnum = 10;

template<class T>
class ThreadPool;

template<class T>
class ThreadData
{
public:
    ThreadPool<T> *threadpool_;
    std::string name_;
public:
    ThreadData(ThreadPool<T>* tp,const std::string& name)
        :threadpool_(tp)
        ,name_(name)
    {}
};

template <class T>
class ThreadPool
{
private:
    static void* handlerTask(void* args)//因为是类内成员所以要加锁static！
    {
        ThreadData<T>* data = static_cast<ThreadData<T>*>(args);
        ThreadPool<T>* tp = data->threadpool_;
        while(true)
        {
            T t;
            {

                LockGuard lock(&tp->mutex_); // 我们使用LockGuard来让其自动加锁和解锁！
                while (tp->IsQueueEmpty())   // 如果任务队列为空，就让线程等待！
                {
                    tp->threadwait(); // 让线程等待！
                }
                // 如果任务队列不为空，那么就取出任务！
                t = tp->pop();//pop的本质是从队列里面,拿到当前线程自己独立的栈中！
            }
            t();//开始执行任务
            // std::cout << data->name_ << " 获取了任务并处理完成！结果是: "<< t()<<std::endl;
        }
        delete data;
        return nullptr;
    }
    ThreadPool(const int &num = gnum)//构造函数私有化！
        :num_(num)
    {
        pthread_mutex_init(&mutex_, nullptr);//初始化锁！
        pthread_cond_init(&cond_, nullptr);//初始化条件变量！
        for(int i = 0; i < num_; ++i)
        {
           threads_.push_back(new Thread());
        } 
    }
    ThreadPool& operator=(const ThreadPool&) = delete;//赋值运算删除！
    ThreadPool(const ThreadPool&) = delete;//拷贝构造函数删除！
public:
    bool IsQueueEmpty(){return task_queue_.empty();}
    void threadwait(){pthread_cond_wait(&cond_, &mutex_);}
    T pop()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }

public:

    void run()//让线程池启动起来！
    {
        for(const auto& t : threads_)
        {
            ThreadData<T>* data = new ThreadData<T>(this,t->Threadname());
            t->start(handlerTask,data);//这个start是Thread类的start！
            std::cout << "thread " << t->Threadname() << " is running" << std::endl;
        }
    }
    // 要加上static!因为单例模式只能有一个
    // 如果是非静态的话,那么就得先创建对象，然后调用给这个对象的非静态成员函数！
    // 但是这样子就不是单例模式了！
    static ThreadPool<T> *getInstance()
    {
        if (pool_ == nullptr)//双判断！除了第一次申请要加锁！后面都不需要！所以叫双判断！
        {
            sinlock_.lock();
            if (pool_ == nullptr)
            {
                if (pool_ == nullptr)
                    pool_ = new ThreadPool<T>();
            }
            sinlock_.unlock();
        }
        return pool_;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
        for(const auto& e : threads_)
        {
            delete e;
        }
    }

    void push(const T&in)//让外部能够向线程池里面放任务！
    {
        LockGuard lock(&mutex_);
        task_queue_.push(in);//向任务队列里面放任务！
        pthread_cond_signal(&cond_);//已经有任务了，那么就唤醒线程！
    }
private:
    int num_;//表示有几个线程
    std::vector<Thread*> threads_;//使用vector管理线程！
    //放的是线程的指针！如果是线程对象就太大了！
    std::queue<T> task_queue_;
    //任务队列！用于存放任务的！
    pthread_mutex_t mutex_;
    //用这个锁来保护共享资源——任务队列！
    pthread_cond_t cond_;
    //让线程等不到任务的时候就去信号量下面等待！

    static ThreadPool<T>* pool_;//我们使用的是懒汉模式！
    static std::mutex sinlock_;//单例模式的锁！用于保护pool_！
    //为了保证多线程的并发访问！
};
//类模板的静态成员变量的初始化！
template<class T>
ThreadPool<T>* ThreadPool<T>::pool_ = nullptr;

template<class T>
std::mutex ThreadPool<T>::sinlock_;